package dungeon;


import static org.junit.Assert.*;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;


import org.junit.Before;
import org.junit.Test;

import condition.ConditionDefault;
import condition.ConditionIsRock;

import border.Wall;

import square.Direction;
import square.NormalSquare;
import square.Rock;
import square.Square;
import square.Temperature;

public class ComposedDungeonTest {

	@Before
	public void setUp() throws Exception {
		cd1 = new ComposedDungeon<Square>(5, 5, 1);
		cd2 = new ComposedDungeon<Square>(5, 5, 0);
		l = new Level<Square>(3, 3, 0);
		s = new Shaft<Square>(3, 0, 0);
		sq1 = new NormalSquare();
		sq2 = new NormalSquare();
		sq3 = new NormalSquare();
		sq4 = new NormalSquare();
		w1 = new Wall(sq1,Direction.SOUTH,false);
		w2 = new Wall(sq2,Direction.SOUTH,false);
		
		l.putDungeonIn(cd2, new Position(1,0,0));
		s.putDungeonIn(cd2, new Position(1,4,0));
		cd2.putDungeonIn(cd1, new Position(0,0,1));
		
		l.addSquare(new Position(1,3,0), sq1);
		cd2.addSquare(new Position(3,3,0),sq2);
		cd1.addSquare(new Position(2, 4, 1), sq3);
		cd1.addSquare(new Position(3,4,1), sq4);
	}
	
	@Test
	public void terminate_singleCase(){
		cd2.terminate();
		assertTrue(cd2.isTerminated());
		assertEquals(0, cd2.getNbSubDungeons());
		assertFalse(cd1.hasAsSubDungeon(cd2));
		assertTrue(l.isTerminated());
		assertTrue(cd2.getContainingDungeon() == null);
		assertTrue(sq3.isTerminated());
	}
	
	@Test
	public void getSquares_singleCase(){
		ArrayList<Square> squares = new ArrayList<Square>();
		Iterator<Square> it = cd1.getSquares(new ConditionDefault());
		while(it.hasNext())
			squares.add(it.next());
		assertTrue(squares.contains(sq1));
		assertTrue(squares.contains(sq2));
		assertTrue(squares.contains(sq3));
		assertTrue(squares.contains(sq4));
		Iterator<Square> it2 = cd1.getSquares(new ConditionIsRock());
		assertFalse(it2.hasNext());
	}
	
	@Test
	public void getSubDungeonAt_TrueCase(){
		assertEquals(cd2,cd1.getSubDungeonAt(new Position(2,3,1)));
	}
	
	@Test
	public void getSubDungeonAt_FalseCase(){
		assertEquals(null,cd1.getSubDungeonAt(new Position(0,0,0)));
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void canHaveAsSubDungeonAt_overlappingDungeon(){
		Shaft<Square> s2 = new Shaft<Square>(2,0,0);
		s2.putDungeonIn(cd2, new Position(3,3,0));
	}
	
	@Test
	public void hasAsSubDungeon_multipledepth(){
		assertTrue(cd1.hasAsSubDungeon(s));
	}
	
	@Test
	public void hasAsSquare_multipleDepth(){
		assertTrue(cd1.hasAsSquare(sq1));
	}
	
	@Test
	public void getPositionOfSquare_multipleDepth(){
		assertEquals(new Position(2,3,1),cd1.getPositionOfSquare(sq1));
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void addSubDungeon_overlappingSubDungeon(){
		(new Level<Square>(1,2,0)).putDungeonIn(cd1, new Position(0,1,1));
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void addSubDungeon_sameDungeon(){
		Shaft<Square> s2 = new Shaft<Square>(1,0, 0);
		s2.putDungeonIn(cd1, new Position(0,1,0));
		s2.putDungeonIn(cd1, new Position(0,1,0));
	}
	
	@Test (expected = IllegalArgumentException.class)
	public void addSquareAt_IllegalPositionInSubDungeon(){
		cd1.addSquare(new Position(1,0,1), new Rock());
	}
	
	@Test
	public void addSquareAt_TrueCase(){
		assertTrue(l.hasAsSquare(sq1));
		assertTrue(s.hasAsSquare(sq3));
		assertTrue(sq1.getBorder(Direction.SOUTH) != null);
		assertTrue(sq3.getBorder(Direction.NORTH) != null);
		assertEquals(sq3,sq1.getBorder(Direction.SOUTH).getOtherSquare(sq1));
		assertEquals(sq2,sq4.getBorder(Direction.NORTH).getOtherSquare(sq4));
	}
	
	@Test
	public void getAllLeafDungeons_singleCase(){
		HashSet<LeafDungeon<Square>> set = cd1.getAllLeafDungeons();
		assertTrue(set.contains(l));
		assertTrue(set.contains(s));
		assertEquals(2,set.size());
	}
	
	@Test
	public void constructBorderWithOtherDungeon_noBorder(){
		cd1.addSquare(new Position(4,3,1), new NormalSquare());
		cd1.addSquare(new Position(4,4,1), new NormalSquare(new Temperature(60), new BigDecimal(30)));
		assertEquals(new Temperature(10).getTemperatureValue(),sq1.getTemperature().getTemperatureValue(),0.5);
		assertEquals(new BigDecimal(5),sq3.getHumidity());
	}
	
	ComposedDungeon<Square> cd1;
	ComposedDungeon<Square> cd2;
	Level<Square> l;
	Shaft<Square> s;
	NormalSquare sq1;
	NormalSquare sq2;
	NormalSquare sq3;
	NormalSquare sq4;
	Wall w1;
	Wall w2;
}
